  /**
   * LICENCIA LGPL:
   * 
   * Esta librería es Software Libre; Usted puede redistribuirla y/o modificarla
   * bajo los términos de la GNU Lesser General Public License (LGPL) tal y como 
   * ha sido publicada por la Free Software Foundation; o bien la versión 2.1 de 
   * la Licencia, o (a su elección) cualquier versión posterior.
   * 
   * Esta librería se distribuye con la esperanza de que sea útil, pero SIN 
   * NINGUNA GARANTÍA; tampoco las implícitas garantías de MERCANTILIDAD o 
   * ADECUACIÓN A UN PROPÓSITO PARTICULAR. Consulte la GNU Lesser General Public 
   * License (LGPL) para más detalles
   * 
   * Usted debe recibir una copia de la GNU Lesser General Public License (LGPL) 
   * junto con esta librería; si no es así, escriba a la Free Software Foundation 
   * Inc. 51 Franklin Street, 5º Piso, Boston, MA 02110-1301, USA o consulte
   * <http://www.gnu.org/licenses/>.
   *
   * Copyright 2011 Agencia de Tecnología y Certificación Electrónica
   */
  package es.accv.arangi.base.device;
  
  import java.security.KeyStore;
  import java.security.KeyStoreException;
  import java.security.Provider;
  import java.security.Security;
  
  import javax.security.auth.callback.PasswordCallback;
  
  import org.apache.log4j.Logger;
  
  import es.accv.arangi.base.exception.device.AppleSafariKeyStoreException;
  import es.accv.arangi.base.exception.device.AppleSafariNotFoundException;
  
  /**
   * Clase para tratar almacenes de claves de llaveros en Mac OS X.<br><br>
   * 
   * NOTA: En esta versión es posible obtener los certificados pero se produce un
   * error al realizar la firma. Si alguien tiene interés puede probar la clase,
   * pero no se debe usar en sistemas en explotación hasta que no se depuren sus
   * errores.
   * 
   * Ejemplo de uso:<br><br>
   * 
   * <code>
   *  IDocument document = new FileDocument(new File ("/documento.txt"));<br>
   * 	AppleSafariManager manager = new AppleSafariManager ();<br>
   * 	String aliases = manager.getAliasNamesList();<br>
   * 	for (int i=0;i<aliases.length;i++) {<br>
   *  &nbsp;&nbsp;System.out.println ("Certificate: " + manager.getCertificate(aliases[i]));<br>
   * 	&nbsp;&nbsp;System.out.println ("Firma: " + manager.signDocument(document, aliases[i])); // Firma con la clave privada del alias<br>
   * 	}<br>
   * </code><br>
   * 
   * @author <a href="mailto:jgutierrez@accv.es">José M Gutiérrez</a>
   */
public class AppleSafariManager extends AbstractBrowserKeyStoreManager {

	/*
	 * Nombre del KeyStore
	 */
	private static final String KEYSTORE_NAME = "KeychainStore";
	
	/*
	 * Logger de la clase
	 */
	Logger logger = Logger.getLogger(AppleSafariManager.class);
	
	/*
	 * Texto del dialogo en el que se pedirá el pin al usuario
	 */
	String textPinDialog = null;
	
	/**
	 * Constructor: inicializa el proveedor de SUN si es necesario para
	 * acceder al repositorio de Safari.
	 * 
	 * @throws AppleSafariKeyStoreException No se puede abrir el almacén de claves de Safari
	 * @throws AppleSafariNotFoundException No existe el almacén de claves de Safari, 
	 * 	probablemente no se encuentre en un entorno Mac OS X
	 */
	public AppleSafariManager () throws AppleSafariKeyStoreException, AppleSafariNotFoundException {
		
		if(!System.getProperty("os.name").startsWith("Mac OS X")) {
			logger.info("[AppleSafariKeyStoreManager]:: El sistema operativo no es Mac OS X sino " + System.getProperty("os.name"));
			throw new AppleSafariNotFoundException("El sistema operativo no es Mac OS X sino " + System.getProperty("os.name"));
		}
		
		//-- El SO es el correcto
		initKeystore();

	}
	
	/**
	 * Constructor: inicializa el proveedor de SUN si es necesario para
	 * acceder al repositorio de Safari.
	 * 
	 * @param pinDialogText texto del dialogo en el que se pedirá el pin al usuario.
	 * 
	 * @throws AppleSafariKeyStoreException No se puede abrir el almacén de claves de Safari
	 * @throws AppleSafariNotFoundException No existe el almacén de claves de Safari, 
	 * 	probablemente no se encuentre en un entorno Mac OS X
	 */
	public AppleSafariManager (String textPinDialog) throws AppleSafariKeyStoreException, AppleSafariNotFoundException {
		
		if(!System.getProperty("os.name").startsWith("Mac OS X")) {
			logger.info("[AppleSafariKeyStoreManager]:: El sistema operativo no es Mac OS X sino " + System.getProperty("os.name"));
			throw new AppleSafariNotFoundException("El sistema operativo no es Mac OS X sino " + System.getProperty("os.name"));
		}
		
		//-- El SO es el correcto
		this.textPinDialog = textPinDialog;
		initKeystore();

	}
	
	//-- Métodos públicos
	
	/**
	 * Cerrar el keystore y eliminar el provider de SUN de la lista de proveedores
	 */
	public void close() {
		logger.debug ("Cerrando Keystore...");

		ks = null;
		
		//-- Eliminar provider de SUN
		logger.debug("[CLOSE]::Eliminando el provider de SUN");
		Security.removeProvider("SunPKCS11-Apple");
		logger.debug("[CLOSE]::Eliminado el provider de SUN");
		
		logger.debug("Cerrado Keystore...OK");
	}
	
	@Override
	public void initialize() {
		if (textPinDialog != null) {
			try {
				initKeystore();
			} catch (AppleSafariKeyStoreException e) {
				logger.info("[AppleSafariKeyStoreManager.initialize]:: Error al reinicializar el KeyStore", e);
			} 
		} else {
			try {
				initKeystore();
			} catch (AppleSafariKeyStoreException e) {
				logger.info("[AppleSafariKeyStoreManager.initialize]:: Error al reinicializar el KeyStore", e);
			} 
		}
		
	}
	
	//-- Implementación
	
	/* (non-Javadoc)
	 * @see es.accv.arangi.base.device.DeviceManager#isAliasFree(java.lang.String)
	 */
	public boolean isAliasFree(String alias){
		
		logger.debug ("[KeyStoreManager.isAliasFree]::Entrada::" + alias);
		
		boolean isFree = false;
		try {
			isFree = !ks.containsAlias(alias);
		} catch (KeyStoreException e) {
			logger.info("[KeyStoreManager.isAliasFree]::Error comprobando si existe el alias '" + alias + "'", e);
		}
		return isFree;
	}
	
	//-- Métodos privados
	
	private void initKeystore() throws AppleSafariKeyStoreException {
		
		this.pin = "";
		this.ksType = STORE_TYPE_APPLE;
		
		//-- Anadir el proveedor de Apple
		try {
			Security.insertProviderAt((Provider)Class.forName("com.apple.crypto.provider.Apple").newInstance(), 0);
		} catch(Throwable e) {
			logger.info("[AppleSafariKeyStoreManager]::No se ha podido abrir el almacén de claves del usuario de Safari", e);
			throw new AppleSafariKeyStoreException("No se ha podido instanciar el proveedor 'com.apple.crypto.provider.Apple'", e);
		}

		//-- Obtener el keystore
		try {
			ks = KeyStore.getInstance(KEYSTORE_NAME);
		} catch(Throwable e) {
			logger.info("[AppleSafariKeyStoreManager]::No se ha podido obtener un keystore de tipo " + KEYSTORE_NAME, e);
			throw new AppleSafariKeyStoreException("No se ha podido obtener un keystore de tipo " + KEYSTORE_NAME, e);
		}

		//-- Cargar el keystore de Safari
		try {
			ks.load(null, null);
		} catch(Throwable e) {
			logger.info("[AppleSafariKeyStoreManager]::No se ha podido cargar el keystore", e);
			throw new AppleSafariKeyStoreException("No se ha podido cargar el keystore", e);
		}

	}
}